﻿#region Using

using System.Collections.Generic;

using Common.Base;

using CommunicationLibrary.TransportData;

using GameLogic.External;

using ServerApplication.GameSession;
using ServerApplication.Interfaces;
using ServerApplication.Networking;

#endregion

namespace ServerApplication
{
    public class Core : INetworkToCore, IMatchmakingManagerToCore, IGameSessionManagerToCore
    {
        private readonly ICoreToGameSessionManager gameSessionManager;

        private readonly ICoreToMatchmakingManager matchmakingManager;

        private readonly ICoreToNetwork networkLayer;

        public Core()
        {
            this.matchmakingManager = new MatchmakingManager(this);
            this.gameSessionManager = new GameSessionManager(this);

            var playerManager = new PlayerManager();
            this.networkLayer = new OutConnectionLayer(playerManager);
            new InConnectionLayer(this, playerManager);
        }

        public Result CancelRegistration(ServerPlayer player)
        {
            if (!this.matchmakingManager.TryCancelMatchmaking(player))
            {
                return Result.Failure("You are not in Matchmaking anymore!");
            }

            return Result.Success;
        }

        public Result Execute(ICommand cmd)
        {
            return this.gameSessionManager.Execute(cmd);
        }

        public Result MarkReady(ServerPlayer player)
        {
            if (!this.gameSessionManager.TryMarkReady(player))
            {
                return Result.Failure("You are not waiting for a game start!");
            }

            return Result.Success;
        }

        public Result PauseGame(ServerPlayer player)
        {
            return this.gameSessionManager.PauseGame(player);
        }

        public Result QuitGame(ServerPlayer player)
        {
            return this.gameSessionManager.QuitGame(player);
        }

        public Result RegisterForMatch(ServerPlayer player)
        {
            if (!this.matchmakingManager.TryEnqueue(player))
            {
                return Result.Failure("You are already in Matchmaking!");
            }

            return Result.Success;
        }

        public Result ResumeGame(ServerPlayer player)
        {
            return this.gameSessionManager.ResumeGame(player);
        }

        public void SendGamePaused(IEnumerable<Identifiable> players)
        {
            foreach (var identifiable in players)
            {
                this.networkLayer.SendGamePausedMessage(identifiable);
            }
        }

        public void SendGameReady(GameState startingState, IEnumerable<Identifiable> players)
        {
            foreach (var player in players)
            {
                this.networkLayer.SendGameReady(player, startingState);
            }
        }

        public void SendGameResumed(IEnumerable<Identifiable> players)
        {
            foreach (var identifiable in players)
            {
                this.networkLayer.SendGameResumedMessage(identifiable);
            }
        }

        public void SendGameStarted(IEnumerable<Identifiable> players)
        {
            foreach (var player in players)
            {
                this.networkLayer.SendGameStarted(player);
            }
        }

        public void SendGameState(GameState state, IEnumerable<Identifiable> receivers)
        {
            foreach (var player in receivers)
            {
                this.networkLayer.SendGameState(state, player);
            }
        }

        public void SendPlayerLost(Identifiable looser, IEnumerable<Identifiable> receivers)
        {
            foreach (var receiver in receivers)
            {
                this.networkLayer.SendGameLostMessage(looser, receiver);
            }
        }

        public void SendPlayerWon(Identifiable player)
        {
            this.networkLayer.SendGameWonMessage(player);
        }

        public void WorkWithMatchedPlayers(IEnumerable<ServerPlayer> players)
        {
            this.gameSessionManager.CreateGameSession(players);
        }
    }
}